package com.googlecode.gwt_control.client.form;

import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 *
 * @author Olafur Gauti Gudmundsson
 */
public abstract class Field {

    protected final String id;
    protected final String title;
    protected final Label label, descriptionLabel;
    protected final Label errorLabel;

    protected FieldValidator notEmptyValidator, validator;
    protected FieldPanel fieldPanel;
    protected boolean valueRequired;
    protected String description;

    public Field( String id, String title ) {
        this(id, title, null);
    }

    public Field( String id, String title, FieldValidator validator ) {
        this.id = id;
        this.title = title;
        this.label = new Label(title);
        label.setStyleName("fieldLabel");
        descriptionLabel = new Label();
        descriptionLabel.setStyleName("fieldLabelDescription");
        this.errorLabel = new Label();
        errorLabel.setStyleName("fieldError");
        errorLabel.setVisible(false);
        this.validator = validator;
    }

    public void onAttach( FieldPanel fieldPanel ) {
        this.fieldPanel = fieldPanel;
    }

    public void setEnabled( boolean enabled ) {
        if ( enabled ) {
            label.removeStyleName("disabled");
            descriptionLabel.removeStyleName("disabled");
        } else {
            label.addStyleName("disabled");
            descriptionLabel.addStyleName("disabled");
        }
    }

    public boolean isEnabled() {
        return true;
    }

    protected void fireFieldChanged() {
        if ( fieldPanel != null ) {
            for ( FieldChangeListener listener : fieldPanel.getFieldChangeListeners() ) {
                listener.onChange(this);
            }
        }
    }

    protected void addToTable( int rowNumber, FlexTable table, Widget widget ) {
        int colNumber = 0;

        // add the label, with top alignment
        FlowPanel labelPanel = new FlowPanel();
        labelPanel.add(label);
        if ( description != null && description.trim().length() > 0 ) {
            descriptionLabel.setText(description);
            labelPanel.add(descriptionLabel);
        }

        table.setWidget(rowNumber, colNumber++, labelPanel);
        table.getFlexCellFormatter().addStyleName(rowNumber, 0, "fieldLabelCell");
        table.getFlexCellFormatter().setVerticalAlignment(rowNumber, 0, HasVerticalAlignment.ALIGN_TOP);

        VerticalPanel widgetPanel = new VerticalPanel();
        widgetPanel.setStyleName("fieldWidgetPanel");
        widgetPanel.add(widget);

        FlowPanel errorPanel = new FlowPanel();
        errorPanel.setStyleName("fieldErrorContainer");
        errorPanel.add(errorLabel);
        widgetPanel.add(errorPanel);

        table.setWidget(rowNumber, colNumber++, widgetPanel);
        table.getFlexCellFormatter().addStyleName(rowNumber, 1, "fieldWidgetCell");
        table.getFlexCellFormatter().setVerticalAlignment(rowNumber, 1, HasVerticalAlignment.ALIGN_TOP);
    }

    public abstract void addToTable( int rowNumber, FlexTable table );

    public boolean validate() {
        FieldValidator theValidator = getValidator();
        if ( theValidator != null ) {
            return theValidator.validate(this);
        } else {
            return true;
        }
    }

    public Label getErrorLabel() {
        return errorLabel;
    }

    public void clearError() {
        errorLabel.setVisible(false);
        errorLabel.setText("");
    }

    public void setError( String errorMsg ) {
        errorLabel.setVisible(true);
        errorLabel.setText(errorMsg);
    }

    public Label getLabel() {
        return label;
    }

    public FieldValidator getValidator() {
        if ( notEmptyValidator != null ) {
            return notEmptyValidator;
        } else {
            return validator;
        }
    }

    public String getId() {
        return id;
    }

    public boolean isEmpty() {
        return false;
    }

    public void setValueRequired(final boolean valueRequired) {
        setValueRequired(valueRequired, null);
    }

    public void setValueRequired(final boolean valueRequired, final String emptyMsg) {
        this.valueRequired = valueRequired;
        if ( valueRequired ) {
            if ( title.trim().length() > 0 ) {
                label.setText(title + " *");
            }
            label.addStyleName("required");
            if ( emptyMsg != null ) {
                notEmptyValidator = new FieldValidator() {
                    public boolean validate(Field field) {
                        if ( field.isEmpty() ) {
                            field.setError(emptyMsg);
                            return false;
                        } else if ( validator != null ) {
                            return validator.validate(field);
                        } else {
                            field.clearError();
                            return true;
                        }
                    }
                };
            }
        } else {
            label.setText(title);
            label.removeStyleName("required");
            notEmptyValidator = null;
        }
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

}
